#pragma once
#include <list>
#include <boost/smart_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>

namespace firebird {

template <class Resource>
struct resource_traits {
	typedef Resource resource_type;

	template <class P1>
	static resource_type* create(const P1 p1) {
		return new resource_type(p1);
	}
};


template <class Resource>
class pool {
public:
	typedef Resource resource_type;
	typedef resource_type* resource_raw_pointer;
	typedef boost::shared_ptr<resource_type> resource_pointer;
	typedef boost::recursive_mutex mutex_type;
	typedef pool<resource_type> this_type;

	template <class P1>
	pool(P1 p1) {
		create_resource_ = boost::bind(&resource_traits<resource_type>::create<P1>, p1);
	}

	~pool() {
	}

	resource_pointer get() {
		boost::lock_guard<mutex_type> guard(mutex_);
		resource_pointer result;
		if (free_list_.size() > 0) {
			result = free_list_.front();
			free_list_.pop_front();
		} else {
			result = create_resource();
		}
		return result;
	}

private:
	resource_pointer create_resource() {
		return resource_pointer(create_resource_(), boost::bind(&pool::add_to_free_list, this, _1));
	}

	void add_to_free_list(resource_type* res) {
		boost::lock_guard<mutex_type> guard(mutex_);
		free_list_.push_back(resource_pointer(res, boost::bind(&pool::add_to_free_list, this, _1)));
	}

	boost::function<resource_raw_pointer()> create_resource_;
	mutex_type mutex_;
	std::list<resource_pointer> free_list_;
};

}